/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dataanalysis.main;

import dataanalysis.ASMODE;
import dataanalysis.CLSMODE;
import dataanalysis.Model;
import dataanalysis.MyUtils;
import dataanalysis.gui.SplashWindow;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import javax.swing.JOptionPane;
import weka.attributeSelection.ASEvaluation;
import weka.attributeSelection.ASSearch;
import weka.attributeSelection.semiAS.SemiAttributeSelector;
import weka.classifiers.Classifier;
import weka.core.Instances;
import weka.experiment.InstanceQuery;
import weka.filters.Filter;

/**
 *
 * @author Administrator
 */
public final class MainApp {

    private final MainDocument m_mainDocument;
    private final MainView m_mainView;
    private final DataProcesser m_dataProcesser;

    public MainApp() throws InterruptedException {
        //显示程序启动画面
        SplashWindow splash = new SplashWindow("src\\dataanalysis\\gui\\img\\splash.jpg");
        splash.setVisible(true);

        m_mainDocument = new MainDocument(this);
        m_mainView = new MainView(this);
        m_dataProcesser = new DataProcesser();

        //退出程序启动画面
        splash.setVisible(false);
        splash.dispose();
    }

    private void applyFilter() {
        try {
            Instances curData = m_mainDocument.getCurInstances();
            Filter filter = m_mainDocument.getFilterValue();
            m_dataProcesser.applyFilter(curData, filter);
            Instances resultData = m_dataProcesser.getFilterData();
            m_mainDocument.setCurInstances(resultData);
            m_mainDocument.updatePreInstances();
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Filter");
        }
    }

    private void startSupAttributeSelection() {
        try {
            Instances curData = m_mainDocument.getCurInstances();
            ASEvaluation evaluator = m_mainDocument.getASEvaluationValue();
            ASSearch searcher = m_mainDocument.getASSearchValue();
            ASMODE ASMode = m_mainDocument.getASMode();
            int numFolds = m_mainDocument.getASFoldNum();
            int seed = m_mainDocument.getASSeed();
            m_dataProcesser.startSupAttributeSelection(curData, evaluator, searcher, ASMode, numFolds, seed);
            Instances resultData = m_dataProcesser.getSelectData();
            m_mainDocument.setCurInstances(resultData);
            m_mainDocument.updateSelectInstances();
            String strASResult = m_dataProcesser.getASResultTxt();
            m_mainDocument.setASResult(strASResult);
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Supvised Attribute Selection");
        }
    }

    private void startClassifier() {
        try {
            Instances curData = m_mainDocument.getCurInstances();
            Classifier classifier = m_mainDocument.getClassifierValue();
            CLSMODE testMode = m_mainDocument.getClsMode();
            int numFolds = m_mainDocument.getClsFoldNum();
            double percent = m_mainDocument.getClsSplitPercent();
            int seed = m_mainDocument.getClsSeed();
            m_dataProcesser.startClassifier(curData, classifier, testMode, numFolds, percent, seed);
            String strClassifierResult = m_dataProcesser.getClassifierResultTxt();
            m_mainDocument.setClassifierResult(strClassifierResult);
            m_mainDocument.setModel(new Model(classifier, new Instances(curData, 0)));
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Classifier");
        }
    }

    private void startPredictByModel(Model model) {
        try {
            Instances curData = m_mainDocument.getCurInstances();
            m_dataProcesser.startPredictByModel(curData, model);
            String strPredictResult = m_dataProcesser.getPredictResultTxt();
            m_mainDocument.setPredictResult(strPredictResult);
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "PredictModel");
        }
    }

    private void startSemiAttributeSelection() {
        try {
            Instances curData = m_mainDocument.getCurInstances();
            SemiAttributeSelector semiSelector = m_mainDocument.getSemiASValue();
            m_dataProcesser.startSemiAttributeSelection(curData, semiSelector);
            Instances resultData = m_dataProcesser.getSelectData();
            m_mainDocument.setCurInstances(resultData);
            m_mainDocument.updateSelectInstances();
            String strASResult = m_dataProcesser.getASResultTxt();
            m_mainDocument.setASResult(strASResult);
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Semi Attribute Selector");
        }
    }

    public void openNewDataFile() {
        try {
            Instances data = m_mainView.getLoaderData();
            if (data == null) {
                return;
            }
            String fullName = m_mainView.getLoaderFileName();
            data.setClassIndex(data.numAttributes() - 1);
            m_mainDocument.openNewInstances(data);
            m_mainView.openNewInstances(data);
            m_mainDocument.setFullFileName(fullName);
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Open File");
        }
    }

    public void setProcessFlowValue(int a, int b, int c) {
        try {
            m_mainDocument.setProcessFlowValue(a, b, c);
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Open File");
        }
    }

    @SuppressWarnings("empty-statement")
    public void runDataProcessThread() {
        Thread dataProcessThread = new Thread() {

            @Override
            @SuppressWarnings("empty-statement")
            public void run() {
                while (!m_mainView.isProgressDlgShow());
                processData();
                showResult();
                m_mainDocument.selectCurData();//将curData重设为当前选择的数据源
                m_mainView.showProcessDlg(false);
            }
        };
        dataProcessThread.start();
        m_mainView.showProcessDlg(true);
//        while (!m_mainView.isProgressDlgShow());
    }

    private void processData() {
        if (m_mainDocument.isPreFlow()) {
            this.applyFilter();
        }
        if (m_mainDocument.isSupASFlow()) {
            this.startSupAttributeSelection();
        } else if (m_mainDocument.isSemiASFlow()) {
            this.startSemiAttributeSelection();
        }
        if (m_mainDocument.isClassifierFlow()) {
            this.startClassifier();
        }
    }

    public void setFilterValueDoc(Filter filter) {
        m_mainDocument.setFilterValue(filter);
    }

    public void setASEvaluationValueDoc(ASEvaluation evaluator) {
        m_mainDocument.setASEvaluationValue(evaluator);
    }

    public void setASSearchValueDoc(ASSearch searcher) {
        m_mainDocument.setASSearchValue(searcher);
    }

    public void setSemiASValueDoc(SemiAttributeSelector semiASSelector) {
        m_mainDocument.setSemiASValue(semiASSelector);
    }

    public void setClassifierValue(Classifier classifier) {
        m_mainDocument.setClassifierValue(classifier);
    }

    public void setSelectedResult(int index) {
        m_mainDocument.setResultIndex(index);
        this.showResult();
    }

    private void showResult() {
        int index = m_mainDocument.getResultIndex();
        m_mainView.openResultPanel(true);
        String str = null;
        switch (index) {
            case 0:
                str = m_mainDocument.getASResult();
                break;
            case 1:
                str = m_mainDocument.getClassifierResult();
                break;
            case 2:
                str = m_mainDocument.getPredictResult();
                break;
            default:
                return;
        }
        m_mainView.setResult(str);
    }

    public void updateAllCapabilitiesFilter() {
        Instances data = m_mainDocument.getCurInstances();
        m_mainView.updateAllCapabilitiesFilter(data);
    }

    public void setCurDataByIndex(int i) {
        try {
            m_mainDocument.setCurDataIndex(i);
            m_mainDocument.selectCurData();
        } catch (Exception ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Set Data Index");
        }
    }

    private void run() {
        m_mainView.showWindow();
    }

    private void setOriDataView() {
        Instances data = m_mainDocument.getOriInstances();
        m_mainView.setDataTableViewData(data);
    }

    private void setPreDataView() {
        Instances data = m_mainDocument.getPreInstances();
        m_mainView.setDataTableViewData(data);
    }

    private void setEditDataView() {
        Instances data = m_mainDocument.getEditInstances();
        m_mainView.setDataTableViewData(data);
    }

    private void setSelectDataView() {
        Instances data = m_mainDocument.getSelectInstances();
        m_mainView.setDataTableViewData(data);
    }

    public void setDataTableViewByIndex(int index) {
        switch (index) {
            case 0:
                this.setOriDataView();
                break;
            case 1:
                this.setPreDataView();
                break;
            case 2:
                this.setEditDataView();
                break;
            case 3:
                this.setSelectDataView();
                break;
        }
    }

    public void saveAllFiles() {

        String fileName = m_mainDocument.getFileName();
        if (fileName == null ? "" == null : fileName.equals("")) {
            return;
        }
        fileName = fileName.substring(0, fileName.lastIndexOf('.'));
        m_mainView.setSaveAllFilesFolderName(fileName);

        if (!m_mainView.showSaveAllFilesDlg()) {
            return;
        }

        String savePath = m_mainView.getSavePath();
        String extention = m_mainView.getDirChooserExtention();

        String date = MyUtils.getDateString();

        String fullName = "";

        String oriName = fileName + "_ori_" + date + extention;
        fullName = savePath + oriName;
        this.saveOriData(fullName);

        String edtName = fileName + "_edt_" + date + extention;
        fullName = savePath + edtName;
        this.saveEditData(fullName);

        String preName = fileName + "_pre_" + date + extention;
        fullName = savePath + preName;
        this.savePreData(fullName);

        String feaName = fileName + "_fea_" + date + extention;
        fullName = savePath + feaName;
        this.saveSelectData(fullName);

        String txtFeaName = fileName + "_fea_" + date + ".txt";
        fullName = savePath + txtFeaName;
        this.saveSelectTxt(fullName);

        String txtClsName = fileName + "_cls_" + date + ".txt";
        fullName = savePath + txtClsName;
        this.saveClassifierTxt(fullName);

        String txtPdtName = fileName + "_pdt_" + date + ".txt";
        fullName = savePath + txtPdtName;
        this.savePredictTxt(fullName);

        String serialModelName = fileName + "_mod_" + date + ".model";
        fullName = savePath + serialModelName;
        this.exportModel(fullName);

        String txtModelName = fileName + "_mod_" + date + ".txt";
        fullName = savePath + txtModelName;
        this.saveModelTxt(fullName);

    }

    private void saveOriData(String fullName) {
        Instances data = m_mainDocument.getOriInstances();
        m_mainView.saveData(fullName, data);
    }

    private void saveEditData(String fullName) {
        Instances data = m_mainDocument.getEditInstances();
        m_mainView.saveData(fullName, data);
    }

    private void savePreData(String fullName) {
        Instances data = m_mainDocument.getPreInstances();
        m_mainView.saveData(fullName, data);
    }

    private void saveSelectData(String fullName) {
        Instances data = m_mainDocument.getSelectInstances();
        m_mainView.saveData(fullName, data);
    }

    private void saveSelectTxt(String fullName) {
        String txt = m_mainDocument.getASResult();
        this.saveTxt(fullName, txt);
    }

    private void saveClassifierTxt(String fullName) {
        String txt = m_mainDocument.getClassifierResult();
        this.saveTxt(fullName, txt);
    }

    private void savePredictTxt(String fullName) {
        String txt = m_mainDocument.getPredictResult();
        this.saveTxt(fullName, txt);
    }

    public void exportModel(String fullName) {
        try {
            FileOutputStream fout = new FileOutputStream(fullName);
            ObjectOutputStream bufferStream = new ObjectOutputStream(fout);
            bufferStream.writeObject(m_mainDocument.getSerialModel());
            bufferStream.flush();
            bufferStream.close();
            fout.close();
        } catch (IOException ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Save Model");
        }
    }

    public void saveModelTxt(String fullName) {
        String txt = m_mainDocument.getTxtModel();
        this.saveTxt(fullName, txt);
    }

    private void saveTxt(String fullName, String txt) {
        if (txt == null || txt.equals("")) {
            return;
        }
        try {
            FileOutputStream fout = new FileOutputStream(fullName);
            BufferedOutputStream bufferStream = new BufferedOutputStream(fout);
            bufferStream.write(txt.getBytes());
            bufferStream.close();
            fout.close();
        } catch (IOException ex) {
            ex.printStackTrace();
            m_mainView.showErrorDlg(ex, "Save Text Results");
        }
    }

    public void setMoreOptions(ASMODE ASMode, int ASFoldNum, int ASSeed, CLSMODE clsMode, int clsFoldNum, double clsSplitPercent, int clsSeed) {
        m_mainDocument.setASMode(ASMode);
        m_mainDocument.setASFoldNum(ASFoldNum);
        m_mainDocument.setASSeed(ASSeed);
        m_mainDocument.setClsMode(clsMode);
        m_mainDocument.setClsFoldNum(clsFoldNum);
        m_mainDocument.setClsSplitPercent(clsSplitPercent);
        m_mainDocument.setClsSeed(clsSeed);
    }

    public void runDataPredictThread(final Model model) {
        Thread dataPredictThread = new Thread() {

            @Override
            @SuppressWarnings("empty-statement")
            public void run() {
                while (!m_mainView.isProgressDlgShow());
                startPredictByModel(model);
                showResult();
                m_mainView.showProcessDlg(false);
            }
        };
        dataPredictThread.start();
        m_mainView.showProcessDlg(true);
    }

    public boolean checkModelCapabilities(Model model) {
        Instances curData = m_mainDocument.getCurInstances();

        if (curData == null) {
            return false;
        }
        Instances trainHeader = model.getDataHeader();
        if (trainHeader == null) {
            return false;
        }
        if (trainHeader.classIndex() > curData.numAttributes() - 1) {
            return false;
        }
        if (curData.classIndex() != trainHeader.classIndex()) {
            return false;
        }
        if (!trainHeader.equalHeaders(curData)) {
            return false;
        }
        return true;
    }

    public void connectDatabase(String URL, String user, String password, String query) {
        try {
            InstanceQuery InstQ = new InstanceQuery();
            InstQ.setDatabaseURL(URL);
            InstQ.setUsername(user);
            InstQ.setPassword(password);
            InstQ.setQuery(query);

            // we have to disconnect, otherwise we can't change the DB!
            if (InstQ.isConnected()) {
                InstQ.disconnectFromDatabase();
            }
            InstQ.connectToDatabase();
            Instances data = InstQ.retrieveInstances();
            if (data == null) {
                return;
            }
            String fullName = m_mainView.getLoaderFileName();
            data.setClassIndex(data.numAttributes() - 1);
            m_mainView.openNewInstances(data);
            m_mainDocument.openNewInstances(data);
            m_mainDocument.setFullFileName(fullName);
            InstQ.disconnectFromDatabase();
        } catch (Exception ex) {
            m_mainView.showErrorDlg(ex, "Connect Database");
        }
    }

    public static void main(String[] args) {
        try {
            new MainApp().run();
        } catch (InterruptedException ex) {
            JOptionPane.showMessageDialog(null,
                    "Problem :" + ex.getMessage(),
                    "应用程序",
                    JOptionPane.ERROR_MESSAGE);
            System.exit(0);
        }
    }
}
